package iamutkarshtiwari.github.io.ananas.editimage;

import iamutkarshtiwari.github.io.ananas.ResourceTable;
import iamutkarshtiwari.github.io.ananas.editimage.fragment.*;
import iamutkarshtiwari.github.io.ananas.editimage.fragment.crop.CropFragment;
import iamutkarshtiwari.github.io.ananas.editimage.fragment.paint.PaintFragment;
import iamutkarshtiwari.github.io.ananas.editimage.utils.BitmapUtils;
import iamutkarshtiwari.github.io.ananas.editimage.utils.MyToast;
import iamutkarshtiwari.github.io.ananas.editimage.utils.PxUtil;
import iamutkarshtiwari.github.io.ananas.editimage.view.*;
import iamutkarshtiwari.github.io.ananas.editimage.widget.RedoUndoController;
import io.reactivex.Single;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.components.*;
import ohos.agp.utils.Matrix;
import ohos.agp.utils.RectFloat;
import ohos.agp.utils.TextTool;
import ohos.agp.window.dialog.CommonDialog;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.global.resource.NotExistException;
import ohos.global.resource.WrongTypeException;
import ohos.media.image.PixelMap;
import ohos.media.image.common.ImageInfo;
import ohos.media.image.common.PixelFormat;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class EditImageAbility extends AbilitySlice {
    private static final String TAG = EditImageAbility.class.getSimpleName();

    public static final int MODE_NONE = 0;
    public static final int MODE_STICKERS = 1;
    public static final int MODE_FILTER = 2;
    public static final int MODE_CROP = 3;
    public static final int MODE_ROTATE = 4;
    public static final int MODE_TEXT = 5;
    public static final int MODE_PAINT = 6;
    public static final int MODE_BEAUTY = 7;
    public static final int MODE_BRIGHTNESS = 8;
    public static final int MODE_SATURATION = 9;

    public String sourceFilePath;
    public String outputFilePath;
    //    public String editorTitle;
    public StickerView stickerView;
    public CropImageView cropPanel;
    public Image mainImage;
    public TextStickerView textStickerView;
    public int mode = MODE_NONE;
    protected boolean isBeenSaved = false;
    protected boolean isPortraitForced = false;
    //    protected boolean isSupportActionBarEnabled = false;
    public CustomPaintView paintView;
    //    public ViewFlipper bannerFlipper;
    public Image brightnessView;
    public Image saturationView;
    public RotateImageView rotatePanel;
    //    public CustomViewPager bottomGallery;
    public StickerFragment stickerFragment;
    public FilterListFragment filterListFragment;
    public CropFragment cropFragment;
    public RotateFragment rotateFragment;
    public AddTextFragment addTextFragment;
    public PaintFragment paintFragment;
    public BeautyFragment beautyFragment;
    public BrightnessFragment brightnessFragment;
    public SaturationFragment saturationFragment;
    protected int numberOfOperations = 0;
    //    private int imageWidth, imageHeight;
    private PixelMap mainBitmap;
    //    private Dialog loadingDialog;
//    private TextView titleView;
    private MainMenuFragment mainMenuFragment;
    private RedoUndoController redoUndoController;
    //    private OnMainBitmapChangeListener onMainBitmapChangeListener;
    private CompositeDisposable compositeDisposable = new CompositeDisposable();
    private PageSlider bottomGallery;
    private float imageScale = 1;
    private float offsetX = 0, offsetY = 0;

    private Text textDone;
    private Text textApply;
    private boolean first = true;
    private StackLayout stackLayout;
    private CommonDialog commonDialog;
    private boolean isApply = false;

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_image_edit);
        getData(intent);
        initView();
    }


    private void getData(Intent intent) {
        sourceFilePath = intent.getStringParam("SourceFilePath");
//        mainBitmap = BitmapUtils.getPixMapFromPath(sourceFilePath);
        outputFilePath = intent.getStringParam("OutputFilePath");
    }

    private void initView() {
        textDone = (Text) findComponentById(ResourceTable.Id_text_done);
        textDone.setClickedListener(new SaveBtnClick());
        textApply = (Text) findComponentById(ResourceTable.Id_text_apply);
        textApply.setClickedListener(new ApplyBtnClick());

        mainImage = (Image) findComponentById(ResourceTable.Id_main_show);
//        mainImage.setPixelMap(mainBitmap);
        findComponentById(ResourceTable.Id_back_edit).setClickedListener(v -> onBackPressed());
        stickerView = (StickerView) findComponentById(ResourceTable.Id_sticker_panel);
        cropPanel = (CropImageView) findComponentById(ResourceTable.Id_crop_panel);
        rotatePanel = (RotateImageView) findComponentById(ResourceTable.Id_rotate_panel);
        textStickerView = (TextStickerView) findComponentById(ResourceTable.Id_text_sticker_panel);
        paintView = (CustomPaintView) findComponentById(ResourceTable.Id_custom_paint_view);
        brightnessView = (Image) findComponentById(ResourceTable.Id_brightness_view);
        saturationView = (Image) findComponentById(ResourceTable.Id_saturation_view);
        bottomGallery = (PageSlider) findComponentById(ResourceTable.Id_bottom_gallery);
        stackLayout = (StackLayout) findComponentById(ResourceTable.Id_stack_layout);

        mainMenuFragment = new MainMenuFragment(this, bottomGallery);
        stickerFragment = new StickerFragment(this, bottomGallery);
        filterListFragment = new FilterListFragment(this, bottomGallery);
        cropFragment = new CropFragment(this, bottomGallery);
        rotateFragment = new RotateFragment(this, bottomGallery);
        paintFragment = new PaintFragment(this, bottomGallery);
        beautyFragment = new BeautyFragment(this, bottomGallery);
        brightnessFragment = new BrightnessFragment(this, bottomGallery);
        saturationFragment = new SaturationFragment(this, bottomGallery);
        addTextFragment = new AddTextFragment(this, bottomGallery);

        //把导航页面单独拿出来，如果放PageSlider  回到0时会重绘，引起scroll滑动
        if (first) {
            first = false;
            stackLayout.addComponent(mainMenuFragment, 0);
        }
        redoUndoController = new RedoUndoController(this, findComponentById(ResourceTable.Id_redo_undo_panel));

        List<ComponentContainer> list = new ArrayList<>();
//        list.add(mainMenuFragment);
        list.add(paintFragment);
        list.add(filterListFragment);
        list.add(cropFragment);
        list.add(rotateFragment);
        list.add(addTextFragment);
        list.add(stickerFragment);
        list.add(brightnessFragment);
        list.add(saturationFragment);
        list.add(beautyFragment);
        bottomGallery.setSlidingPossible(false);  //不能滑动
        bottomGallery.setOrientation(Component.HORIZONTAL);
        bottomGallery.setProvider(getProvider(list));
        loadImageFromFile(mainBitmap, sourceFilePath);
    }

    private PageSliderProvider getProvider(List<ComponentContainer> list) {
        return new PageSliderProvider() {
            @Override
            public int getCount() {
                return list.size();
            }

            @Override
            public Object createPageInContainer(ComponentContainer componentContainer, int i) {
                Component component = list.get(i);
                component.setWidth(PxUtil.screenWidth());
                componentContainer.addComponent(component);  //一定要实现，页面显示自定义的view
//                component.setMarginTop(25);
                return component;
            }

            @Override
            public void destroyPageFromContainer(ComponentContainer componentContainer, int i, Object obj) {
                //一定要实现否则切换页面的时候会报错
                if (componentContainer == null) {
                    return;
                }
                if (obj instanceof Component) {
                    componentContainer.removeComponent((Component) obj);
                }
            }

            @Override
            public boolean isPageMatchToObject(Component component, Object o) {
                return false;
            }
        };
    }

    @Override
    protected void onBackPressed() {
        switch (mode) {
            case MODE_STICKERS:
                stickerFragment.backToMain();
                break;
            case MODE_FILTER:
                filterListFragment.backToMain();
                break;
            case MODE_CROP:
                cropFragment.backToMain();
                break;
            case MODE_ROTATE:
                rotateFragment.backToMain();
                break;
            case MODE_TEXT:
                addTextFragment.backToMain();
                break;
            case MODE_PAINT:
                paintFragment.backToMain();
                break;
            case MODE_BEAUTY:
                beautyFragment.backToMain();
                break;
            case MODE_BRIGHTNESS:
                brightnessFragment.backToMain();
                break;
            case MODE_SATURATION:
                saturationFragment.backToMain();
                break;
            default:
                if (!canAutoExit()) {
                    initDialog();
                } else {
                    onSaveTaskDone();
                }
//                }
//                else {
//                    AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
//                    alertDialogBuilder.setMessage(R.string.iamutkarshtiwari_github_io_ananas_exit_without_save)
//                            .setCancelable(false).setPositiveButton(R.string.iamutkarshtiwari_github_io_ananas_confirm, (dialog, id) -> finish()).setNegativeButton(R.string.iamutkarshtiwari_github_io_ananas_cancel, (dialog, id) -> dialog.cancel());
//
//                    AlertDialog alertDialog = alertDialogBuilder.create();
//                    alertDialog.show();
//                }
                break;
        }
    }

    private void initDialog() {
        Component componentDialog = LayoutScatter.getInstance(getContext()).parse(ResourceTable.Layout_view_dialog, null, false);
        Text tvContent = (Text) componentDialog.findComponentById(ResourceTable.Id_tv_content);
        Component confirm = componentDialog.findComponentById(ResourceTable.Id_confirm);
        Component cancel = componentDialog.findComponentById(ResourceTable.Id_cancel);
        tvContent.setText("The edited image is not saved. Do you want to exit?");
        confirm.setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component component) {
                commonDialog.hide();
                terminate();
            }
        });
        cancel.setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component component) {
                commonDialog.hide();
            }
        });
        commonDialog = new CommonDialog(getContext()).setContentCustomComponent(componentDialog);
        commonDialog.show();
    }

    /**
     * 改变显示图像
     *
     * @param newBit            新图像
     * @param needPushUndoStack 是否加入undo栈
     */
    public void changeMainBitmap(PixelMap newBit, boolean needPushUndoStack) {
        if (newBit == null)
            return;

        if (mainBitmap == null || mainBitmap != newBit) {
            if (needPushUndoStack) {
                redoUndoController.switchMainBit(mainBitmap, newBit);
                increaseOpTimes();
            }

            mainBitmap = newBit;
            mainImage.setPixelMap(mainBitmap);//setImageBitmap
//            mainImage.setDisplayType(ImageViewTouchBase.DisplayType.FIT_TO_SCREEN);

//            if (mode == MODE_TEXT) {
//                onMainBitmapChangeListener.onMainBitmapChange();
        }
    }

    protected void onSaveTaskDone() {
        Intent returnIntent = new Intent();
        returnIntent.setParam("SourceFilePath", sourceFilePath);
        returnIntent.setParam("OutputFilePath", outputFilePath);
        returnIntent.setParam("IS_IMAGE_EDITED", numberOfOperations > 0);

        setResult(returnIntent);
        terminate();//finish();
    }

    protected void doSaveImage() {
        if (numberOfOperations <= 0)
            return;

        compositeDisposable.clear();

        Disposable saveImageDisposable = saveImage(mainBitmap)
//                .subscribeOn(Schedulers.io())
//                .observeOn(Schedulers.mainThread())
//                .doOnSubscribe(subscriber -> loadingDialog.show())
//                .doFinally(() -> loadingDialog.dismiss())
                .subscribe(result -> {
                    if (result) {
                        resetOpTimes();
                        onSaveTaskDone();
                    } else {
                        showToast(ResourceTable.String_iamutkarshtiwari_github_io_ananas_save_error);
                    }
                }, e -> showToast(ResourceTable.String_iamutkarshtiwari_github_io_ananas_save_error));

        compositeDisposable.add(saveImageDisposable);
    }

    //    private boolean saveImage(PixelMap finalBitmap) {
    private Single<Boolean> saveImage(PixelMap finalBitmap) {
        return Single.fromCallable(() -> {
            if (TextTool.isNullOrEmpty(outputFilePath))
                return false;

            //需要copy一份，否则保存失败
            PixelMap.InitializationOptions opt = new PixelMap.InitializationOptions();
            opt.pixelFormat = PixelFormat.ARGB_8888;
            opt.editable = true;
            PixelMap pixelMap = PixelMap.create(finalBitmap, opt);

            return BitmapUtils.saveBitmap(pixelMap, outputFilePath);
        });
    }

    private void loadImageFromFile(PixelMap pixelMap, String filePath) {
        compositeDisposable.clear();

        Disposable loadImageDisposable = loadImage(pixelMap, filePath)
//                .subscribeOn(Schedulers.io())
//                .observeOn(Schedulers.mainThread())
//                .doOnSubscribe(subscriber -> loadingDialog.show())
//                .doFinally(() -> loadingDialog.dismiss())
                .subscribe(processedBitmap -> changeMainBitmap(processedBitmap, false),
                        e -> showToast(ResourceTable.String_iamutkarshtiwari_github_io_ananas_save_error));

        compositeDisposable.add(loadImageDisposable);
    }

    private Single<PixelMap> loadImage(PixelMap pixelMap, String filePath) {
        return Single.fromCallable(() -> {
//             BitmapUtils.getPixMapFromPath(filePath);

            //需要copy一份，否则显示失败
            PixelMap.InitializationOptions opt = new PixelMap.InitializationOptions();
            opt.pixelFormat = PixelFormat.ARGB_8888;
            opt.editable = true;
            return PixelMap.create(pixelMap, opt);
        });
    }

    /**
     * 应用或保存
     *
     * @param edit
     */
    public void saveOrApply(boolean edit) {
        setSaveOrApplyAnimation(edit);
        isApply = true;
    }

    @Override
    public void onActive() {
        super.onActive();
    }

    @Override
    public void onForeground(Intent intent) {
        super.onForeground(intent);
    }

    private void showToast(int resId) {
        try {
            MyToast.show(this, getResourceManager().getElement(resId).getString());
        } catch (IOException | NotExistException | WrongTypeException e) {
            MyToast.show(this, "Other error!");
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
//        compositeDisposable.dispose();
        if (filterListFragment != null) {
            filterListFragment.compositeDisposable.dispose();
        }
        if (redoUndoController != null) {
            redoUndoController.onDestroy();
        }

        if (!isPortraitForced) {
//            setLockScreenOrientation(false);
        }

        if (null != mainBitmap && !mainBitmap.isReleased()) {
            mainBitmap.release();
            mainBitmap = null;
        }

        if (stackLayout != null) {
            stackLayout.removeComponentAt(0);
        }

    }

    /**
     * 增加图像操作次数
     */
    public void increaseOpTimes() {
        numberOfOperations++;
        isBeenSaved = false;
    }

    /**
     * 能否自动退出
     *
     * @return 当前对图像无操作可以退出，返回true，否则为false
     */
    public boolean canAutoExit() {
        return isBeenSaved || numberOfOperations == 0;
    }

    /**
     * 重置操作次数
     */
    public void resetOpTimes() {
        isBeenSaved = true;
    }

    /**
     * 设置是否显示图像
     *
     * @param visibility
     */
    public void setMainImageVisibility(int visibility) {
        mainImage.setVisibility(visibility);
    }

    /**
     * 获取显示图像的PixelMap
     *
     * @return PixelMap
     */
    public PixelMap getMainBit() {
        return mainBitmap;
    }

    /**
     * 设置显示图像的PixelMap
     *
     * @param pixelMap
     */
    public void setMainBit(PixelMap pixelMap) {
        mainBitmap = pixelMap;
    }

    /**
     * 获取显示图像的Rect
     *
     * @return Rect
     */
    public RectFloat getBitmapRect() {
        offsetX = offsetY = 0;

        ImageInfo info = mainBitmap.getImageInfo();
        int compWidth = mainImage.getWidth();
        int compHeight = mainImage.getHeight();

        float scaleX = (float) compWidth / info.size.width;
        float sacleY = (float) compHeight / info.size.height;
        imageScale = Math.min(scaleX, sacleY);

        float newWidth = info.size.width * imageScale;
        float newHeight = info.size.height * imageScale;

        if (newWidth < compWidth) {
            offsetX = (compWidth - newWidth) / 2;
        }
        if (newHeight < compHeight) {
            offsetY = (compHeight - newHeight) / 2;
        }

        RectFloat rect = new RectFloat(offsetX, offsetY, offsetX + newWidth, offsetY + newHeight);
        return rect;
    }

    /**
     * 获取显示图像的视图矩阵
     *
     * @return 矩阵
     */
    public Matrix getImageViewMatrix() {
        getBitmapRect();

        Matrix matrix = new Matrix();
        matrix.translate(offsetX, offsetY);
        matrix.scale(imageScale, imageScale);

        return matrix;
    }

//    private void SaveBtnClick() {
//        if (numberOfOperations == 0) {
//            onSaveTaskDone();
//        } else {
//            doSaveImage();
//        }
//
//    }

    private final class SaveBtnClick implements Component.ClickedListener {
        @Override
        public void onClick(Component v) {
            if (numberOfOperations == 0) {
                onSaveTaskDone();
            } else {
                doSaveImage();
            }
        }
    }


    private final class ApplyBtnClick implements Component.ClickedListener {
        @Override
        public void onClick(Component v) {
//            if (mode != MODE_NONE) {
//                saveOrApply(false);
//            }
            switch (mode) {
                case MODE_STICKERS:
                    stickerFragment.applyStickers();
                    break;
                case MODE_FILTER:
                    filterListFragment.applyFilterImage();
                    break;
                case MODE_CROP:
                    cropFragment.applyCropImage();
                    break;
                case MODE_ROTATE:
                    rotateFragment.applyRotateImage();
                    break;
                case MODE_TEXT:
                    addTextFragment.applyTextImage();
                    break;
                case MODE_PAINT:
                    paintFragment.savePaintImage();
                    break;
                case MODE_BEAUTY:
                    beautyFragment.applyBeauty();
                    break;
                case MODE_BRIGHTNESS:
                    brightnessFragment.applyBrightness();
                    break;
                case MODE_SATURATION:
                    saturationFragment.applySaturation();
                    break;
            }
        }
    }

    public void setPaintFragmentVisible() {
        paintFragment.onShow();
    }

    public void setFilterListFragmentVisible() {
        filterListFragment.onShow();
    }

    public void setCropFragmentVisible() {
        cropFragment.onShow();
    }

    public void setRotateFragmentVisible() {
        rotateFragment.onShow();
    }

    public void setAddTextFragmentVisible() {
        addTextFragment.onShow();
    }

    public void setBrightnessFragmentVisible() {
        brightnessFragment.onShow();
    }

    public void setSaturationFragmentVisible() {
        saturationFragment.onShow();
    }

    public void setStickerFragmentVisible() {
        stickerFragment.onShow();
    }

    public void setBeautyFragmentVisible() {
        beautyFragment.onShow();
    }

    float value = PxUtil.vp2px(55);
    AnimatorProperty animatorProperty1 = new AnimatorProperty().setDuration(400).moveFromY(0).moveToY(-value);
    AnimatorProperty animatorProperty2 = new AnimatorProperty().setDuration(400).moveFromY(value).moveToY(0);
    EventHandler current = new EventHandler(EventRunner.getMainEventRunner());

    public void setSaveOrApplyAnimation(boolean edit) {
        Text top = textDone;
        Text bottom = textApply;
        if (!edit) {
            top = textApply;
            bottom = textDone;
        }
        String text = bottom.getText();
        bottom.setText("");
        animatorProperty1.setTarget(top);
        animatorProperty2.setTarget(bottom);
        animatorProperty1.start();
        animatorProperty2.start();
        Text finalBottom = bottom;
        current.postTask(() -> finalBottom.setText(text), 170);
    }
}
